package com.prs.crm.action.flow;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import org.courser.struts.BaseAction;
import org.courser.ui.PaginationSupport;
import org.hibernate.criterion.DetachedCriteria;

import com.prs.crm.context.ToolKits;
import com.prs.crm.domain.flow.WorkFlow;
import com.prs.crm.domain.flow.WorkFlowHandler;
import com.prs.crm.domain.flow.WorkFlowInstance;
import com.prs.crm.domain.flow.WorkFlowInstanceNode;
import com.prs.crm.domain.flow.WorkFlowNode;
import com.prs.crm.domain.flow.WorkFlowType;
import com.prs.crm.domain.hr.Dept;
import com.prs.crm.domain.hr.Role;
import com.prs.crm.domain.sys.Form;
import com.prs.crm.exception.InValidException;
import com.prs.crm.service.flow.WorkFlowInstanceService;
import com.prs.crm.service.flow.WorkFlowService;
import com.prs.crm.service.flow.WorkFlowTypeService;
import com.prs.crm.service.hr.DeptService;
import com.prs.crm.service.hr.PersonService;
import com.prs.crm.service.hr.RoleService;
import com.prs.crm.service.sys.FormService;

public class WorkFlowInstanceAction extends BaseAction {

	private static final long serialVersionUID = -3039132255194757479L;

	private WorkFlowInstanceService workflowInstanceService;

	private WorkFlowTypeService workflowTypeService;

	private WorkFlowService workflowService;

	private FormService formService;

	private DeptService deptService;

	private RoleService roleService;

	private PersonService personService;

	private WorkFlowInstance instance;

	private PaginationSupport pagination;

	private Collection<WorkFlowType> flowTypes;

	private Collection<WorkFlow> workflows;

	private Collection<Form> forms;

	private List<Role> handleRoles;

	private List<Dept> handleDepts;

	private List<WorkFlowHandler> handlers;

	private Integer[] types;

	private String[] principals;

	private String[] executors;

	private String describe;

	public void setWorkflowInstanceService(
			WorkFlowInstanceService workflowInstanceService) {
		this.workflowInstanceService = workflowInstanceService;
	}

	public WorkFlowInstanceService getWorkflowInstanceService() {
		return workflowInstanceService;
	}

	public void setWorkflowService(WorkFlowService workflowService) {
		this.workflowService = workflowService;
	}

	public WorkFlowService getWorkflowService() {
		return workflowService;
	}

	public void setWorkflowTypeService(WorkFlowTypeService workflowTypeService) {
		this.workflowTypeService = workflowTypeService;
	}

	public WorkFlowTypeService getWorkflowTypeService() {
		return workflowTypeService;
	}

	public void setDeptService(DeptService deptService) {
		this.deptService = deptService;
	}

	public DeptService getDeptService() {
		return deptService;
	}

	public PersonService getPersonService() {
		return personService;
	}

	public void setPersonService(PersonService personService) {
		this.personService = personService;
	}

	public void setRoleService(RoleService roleService) {
		this.roleService = roleService;
	}

	public RoleService getRoleService() {
		return roleService;
	}

	public void setHandleDepts(List<Dept> handleDepts) {
		this.handleDepts = handleDepts;
	}

	public List<Dept> getHandleDepts() {
		return handleDepts;
	}

	public void setFormService(FormService formService) {
		this.formService = formService;
	}

	public FormService getFormService() {
		return formService;
	}

	public void setHandleRoles(List<Role> handleRoles) {
		this.handleRoles = handleRoles;
	}

	public List<Role> getHandleRoles() {
		return handleRoles;
	}

	public void setInstance(WorkFlowInstance instance) {
		this.instance = instance;
	}

	public WorkFlowInstance getInstance() {
		return instance;
	}

	public void setForms(Collection<Form> forms) {
		this.forms = forms;
	}

	public Collection<Form> getForms() {
		return forms;
	}

	public void setDescribe(String describe) {
		this.describe = describe;
	}

	public String getDescribe() {
		return describe;
	}

	public void setPagination(PaginationSupport pagination) {
		this.pagination = pagination;
	}

	public PaginationSupport getPagination() {
		return pagination;
	}

	public void setWorkflows(Collection<WorkFlow> workflows) {
		this.workflows = workflows;
	}

	public void setFlowTypes(Collection<WorkFlowType> flowTypes) {
		this.flowTypes = flowTypes;
	}

	public Collection<WorkFlowType> getFlowTypes() {
		return flowTypes;
	}

	public Collection<WorkFlow> getWorkflows() {
		return workflows;
	}

	public void setTypes(Integer[] types) {
		this.types = types;
	}

	public Integer[] getTypes() {
		return types;
	}

	public void setExecutors(String[] executors) {
		this.executors = executors;
	}

	public String[] getExecutors() {
		return executors;
	}

	public void setPrincipals(String[] principals) {
		this.principals = principals;
	}

	public String[] getPrincipals() {
		return principals;
	}

	private List<WorkFlowHandler> getHandlers() {
		if ((handlers == null || handlers.size() < 1) && handleRoles != null
				&& handleDepts != null) {
			handlers = new ArrayList<WorkFlowHandler>();
			for (int i = 0; i < handleRoles.size(); i++) {
				WorkFlowHandler handler = new WorkFlowHandler();
				if (types[i] == 1) {
					handler.setRole(handleRoles.get(i));
					handler.setDept(handleDepts.get(i));
				} else {
					handler.setPrincipal(this.getPersonService().get(
							Integer.parseInt(principals[i])));
					if (executors != null && executors.length > i
							&& executors[i].trim().length() > 0) {
						handler
								.addExecutors(this
										.getPersonService()
										.findPersons(
												ToolKits
														.convertStringAryToIntAry(executors[i]
																.split(","))));
					}
				}
				handlers.add(handler);
			}
		}
		return handlers;
	}

	@Action("listFlowInstance")
	public String execute() {
		DetachedCriteria criteria = this.getPaginationHelper().createQuery(
				WorkFlowInstance.class);
		this.setPagination(this.getWorkflowService().listByPage(criteria,
				getPaginationHelper().prepare(pagination)));
		return SUCCESS;
	}

	@Action("editFlowInstance")
	public String edit() {
		this.setFlowTypes(this.getWorkflowTypeService().getAllTypes());
		this.setForms(this.getFormService().getAllForm());
		this.setWorkflows(this.getWorkflowService().getEnableFlows());
		return SUCCESS;
	}

	@Action(value = "saveFlowInstance", results = {
			@Result(name = "success", type = "redirect", location = "listFlowInstance"),
			@Result(name = "error", type = "chain", location = "editFlowInstance"),
			@Result(name = "input", location = "/flow/setInstanceHandler.ftl") })
	public String save() {
		if (instance.getName() == null || "".equals(instance.getName().trim())) {
			addActionError("名称不能为空");
			return ERROR;
		}
		if (instance.getFlow() == null) {
			addActionError("定义不能为空");
			return ERROR;
		}
		if (instance.getForm() == null) {
			addActionError("表单不能为空");
			return ERROR;
		}
		if (instance.getType() == null) {
			addActionError("类型不能为空");
			return ERROR;
		}
		try {
			String result = SUCCESS;
			if (instance.getId() == null) {
				setInstanceHandler();
				result = INPUT;
			}
			this.getWorkflowInstanceService().save(instance, null);

			return result;
		} catch (InValidException e) {
			this.addActionError(e.getMessage());
			return ERROR;
		}
	}

	@Action("setInstanceHandler")
	public String setInstanceHandler() {
		this.setHandleDepts(new ArrayList<Dept>());
		this.setHandleRoles(new ArrayList<Role>());
		this.getHandleDepts().addAll(this.getDeptService().getAllDepts());
		this.getHandleRoles().addAll(this.getRoleService().getAllRoles());
		return SUCCESS;
	}

	@Action(value = "saveInstanceHandler", results = {
			@Result(name = "success", type = "redirect", location = "listFlowInstance"),
			@Result(name = "error", type = "chain", location = "setInstanceHandler") })
	public String saveInstanceHandler() {
		try {
			this.getWorkflowInstanceService()
					.save(instance, this.getHandlers());

			return SUCCESS;
		} catch (InValidException e) {
			this.addActionError(e.getMessage());
			// setInstanceHandler();
			return ERROR;
		}
	}

	@Action(value = "removeFlowInstance", results = { @Result(name = "success", type = "redirect", location = "listFlowInstance") })
	public String remove() {
		this.getWorkflowInstanceService().remove(instance);
		return SUCCESS;
	}

	@Action(value = "enableFlowInstance", results = { @Result(name = "success", type = "redirect", location = "listFlowInstance") })
	public String enable() {
		this.getWorkflowInstanceService().executeEnable(instance);
		return SUCCESS;
	}

	@Action(value = "disableFlowInstance", results = { @Result(name = "success", type = "redirect", location = "listFlowInstance") })
	public String disable() {
		this.getWorkflowInstanceService().executeDisable(instance);
		return SUCCESS;
	}

	@Action(value = "getInstanceDescribe", results = { @Result(name = "success", type = "json", params = {
			"root", "describe" }) })
	public String getInstanceDescribe() {
		Map<Integer, WorkFlowInstanceNode> nodeMap = new HashMap<Integer, WorkFlowInstanceNode>();
		for (WorkFlowInstanceNode instanceNode : instance.getNodes()) {
			nodeMap.put(instanceNode.getFlownode().getId(), instanceNode);
		}
		int i = 1;
		String nodestr = null;
		for (WorkFlowNode node : instance.getFlow().getNodes()) {
			WorkFlowInstanceNode instanceNode = nodeMap.get(node.getId());
			nodestr = String.valueOf(i++);
			if (instanceNode.getHandler().getRole() != null)
				nodestr += instanceNode.getHandler().getDept().getName() + "-"
						+ instanceNode.getHandler().getRole().getName();
			else
				nodestr += instanceNode.getHandler().getPrincipal().getResume()
						.getName();
			nodestr += "(" + node.getName() + ")";
			this.describe = (this.describe == null) ? nodestr : describe + ";"
					+ nodestr;
		}
		return SUCCESS;
	}

}
